/**
 * 
 */
package de.cbf.cam.dsa.facet.talent;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlTransient;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import de.cbf.cam.dsa.facet.talent.helper.BeTypeValue;
import de.cbf.cam.dsa.facet.talent.helper.CompensationTalentReference;
import de.cbf.util.entity.facet.constants.ConstantsFontColorLogView;
import de.cbf.util.entity.facet.entities.FacetOfEntity;
import de.cbf.util.entity.facet.util.TextPartStyled;
import de.cbf.util.uuidheader.entities.UUIDHeader;
import de.cbf.util.uuidheader.exceptions.EntityMergeException;

/**
 * @author Nebelritter
 *
 */
@XmlRootElement(name="talent")
@XmlAccessorType(XmlAccessType.FIELD)
public class FacetTalent extends FacetOfEntity implements FacetTalentConstants{
	private static final Log logger = LogFactory.getLog(FacetTalent.class);
		
	protected String fTalentType; //base, special, profession talent
	protected String fAttributeFirst;
	protected String fAttributeSecond;
	protected String fAttributeThird;
	
	protected Integer fRaiseColumn;
	@XmlElementWrapper(name="be_sources")
	@XmlElement(name="be_source_values")
	protected List<BeTypeValue> fBeSources;
	protected Boolean fPureATCombatTalent;
	
	@XmlElementWrapper(name="specializations")
	@XmlElement(name="specialization")
	protected List<String> fSpecializations;
	
	@XmlElementWrapper(name="compensationTalents")
	@XmlElement(name="talent")
	protected List<CompensationTalentReference> fCompensationTalents;
	
	public FacetTalent() {
		super();	
	}
	
	

	/* (non-Javadoc)
	 * @see de.cbf.util.uuidheader.entities.NamedEntity#init()
	 */
	@Override
	protected void init() {
		super.init();
		fTalentType			 = UNSET_TalentType;
		fAttributeFirst		 = UNSET_AttributeFirst;
		fAttributeSecond	 = UNSET_AttributeSecond;
		fAttributeThird		 = UNSET_AttributeThird;
		fRaiseColumn 		 = UNSET_RaiseColumn;		
		fPureATCombatTalent  = UNSET_PureATCombatTalent;
		fBeSources			 = new ArrayList<BeTypeValue>() ;
		fSpecializations	 = new ArrayList<String>();
		fCompensationTalents = new ArrayList<CompensationTalentReference>();
		addDefault();
	}	
	
	protected void addDefault() {
		BeTypeValue defaultValue = new BeTypeValue();
		defaultValue.setName(BE_SOURCE_DEFAULT);
		defaultValue.setMathType(MATH_TYPE_ADD);
		defaultValue.setValue(0);
		fBeSources.add(defaultValue);		
	}
	
	public Integer calcBeValue(Map<String,Integer> beSource2beValue,int calcType){
		Integer result = 0;
		for (String key : beSource2beValue.keySet()) {
			BeTypeValue typeValue = findBeTypeValueByName(key);
			if(typeValue != null){
				Integer currentBE = beSource2beValue.get(key);
				Integer calculatedBE = typeValue.calculateBE(currentBE);
				switch (calcType) {
				case BE_CALC_TYPE_HIGHEST:{
					if(result < calculatedBE){
						result = calculatedBE;
					}
					break;
				}
				case BE_CALC_TYPE_ADD:{
					result += calculatedBE;
					break;
				}
				default:
					logger.error("Unknown calcType: "+calcType);
					break;
				}				
			}
		}		
		return result;
	}
	
	protected BeTypeValue findBeTypeValueByName(String key) {
		for (BeTypeValue typeValue : fBeSources) {
			if(typeValue.getName().equals(key)){
				return typeValue;
			}
		}
		return null;
	}

	/* (non-Javadoc)
	 * @see java.lang.Object#hashCode()
	 */
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = super.hashCode();
		result = prime * result
				+ ((fAttributeFirst == null) ? 0 : fAttributeFirst.hashCode());
		result = prime
				* result
				+ ((fAttributeSecond == null) ? 0 : fAttributeSecond.hashCode());
		result = prime * result
				+ ((fAttributeThird == null) ? 0 : fAttributeThird.hashCode());
		result = prime
				* result
				+ ((fCompensationTalents == null) ? 0 : fCompensationTalents
						.hashCode());
		result = prime * result + ((fBeSources == null) ? 0 : fBeSources.hashCode());
		result = prime
				* result
				+ ((fPureATCombatTalent == null) ? 0 : fPureATCombatTalent
						.hashCode());
		result = prime * result
				+ ((fRaiseColumn == null) ? 0 : fRaiseColumn.hashCode());
		result = prime
				* result
				+ ((fSpecializations == null) ? 0 : fSpecializations.hashCode());
		result = prime * result
				+ ((fTalentType == null) ? 0 : fTalentType.hashCode());
		return result;
	}

	/* (non-Javadoc)
	 * @see java.lang.Object#equals(java.lang.Object)
	 */
	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (!super.equals(obj))
			return false;
		if (getClass() != obj.getClass())
			return false;
		FacetTalent other = (FacetTalent) obj;
		if (fAttributeFirst == null) {
			if (other.fAttributeFirst != null)
				return false;
		} else if (!fAttributeFirst.equals(other.fAttributeFirst))
			return false;
		if (fAttributeSecond == null) {
			if (other.fAttributeSecond != null)
				return false;
		} else if (!fAttributeSecond.equals(other.fAttributeSecond))
			return false;
		if (fAttributeThird == null) {
			if (other.fAttributeThird != null)
				return false;
		} else if (!fAttributeThird.equals(other.fAttributeThird))
			return false;
		if (fCompensationTalents == null) {
			if (other.fCompensationTalents != null)
				return false;
		} else if (!fCompensationTalents.equals(other.fCompensationTalents))
			return false;
		if (fBeSources == null) {
			if (other.fBeSources != null)
				return false;
		} else if (!fBeSources.equals(other.fBeSources))
			return false;
		if (fPureATCombatTalent == null) {
			if (other.fPureATCombatTalent != null)
				return false;
		} else if (!fPureATCombatTalent.equals(other.fPureATCombatTalent))
			return false;
		if (fRaiseColumn == null) {
			if (other.fRaiseColumn != null)
				return false;
		} else if (!fRaiseColumn.equals(other.fRaiseColumn))
			return false;
		if (fSpecializations == null) {
			if (other.fSpecializations != null)
				return false;
		} else if (!fSpecializations.equals(other.fSpecializations))
			return false;
		if (fTalentType == null) {
			if (other.fTalentType != null)
				return false;
		} else if (!fTalentType.equals(other.fTalentType))
			return false;
		return true;
	}
	

	@Override
	public List<TextPartStyled> getFacetStyledDescription() {
		List<TextPartStyled> textStyleInfo = new ArrayList<TextPartStyled>();		
		TextPartStyled textPart;
		//fTalentType
		textPart = new TextPartStyled();
		textPart.setText("\t"+TEXT_LOG_TalentType);
		textPart.setStyleConstant(ConstantsFontColorLogView.STYLE_CATEGORY);	
		textStyleInfo.add(textPart);
		//fTalentType value
		textPart = new TextPartStyled();
		textPart.setText(fTalentType+" \n");
		textPart.setStyleConstant(ConstantsFontColorLogView.STYLE_VALUE);		
		textStyleInfo.add(textPart );
		
		//fAttributeFirst
		textPart = new TextPartStyled();
		textPart.setText("\t"+TEXT_LOG_AttributeFirst);
		textPart.setStyleConstant(ConstantsFontColorLogView.STYLE_CATEGORY);		
		textStyleInfo.add(textPart);
		//fAttributeFirst value
		textPart = new TextPartStyled();
		textPart.setText(fAttributeFirst+" \n");
		textPart.setStyleConstant(ConstantsFontColorLogView.STYLE_VALUE);		
		textStyleInfo.add(textPart );
		
		//fAttributeSecond
		textPart = new TextPartStyled();
		textPart.setText("\t"+TEXT_LOG_AttributeSecond);
		textPart.setStyleConstant(ConstantsFontColorLogView.STYLE_CATEGORY);		
		textStyleInfo.add(textPart);
		//fAttributeSecond value
		textPart = new TextPartStyled();
		textPart.setText(fAttributeSecond+" \n");
		textPart.setStyleConstant(ConstantsFontColorLogView.STYLE_VALUE);		
		textStyleInfo.add(textPart );
		
		//fAttributeThird
		textPart = new TextPartStyled();
		textPart.setText("\t"+TEXT_LOG_AttributeThird);
		textPart.setStyleConstant(ConstantsFontColorLogView.STYLE_CATEGORY);		
		textStyleInfo.add(textPart);
		//fAttributeThird value
		textPart = new TextPartStyled();
		textPart.setText(fAttributeThird+" \n");
		textPart.setStyleConstant(ConstantsFontColorLogView.STYLE_VALUE);		
		textStyleInfo.add(textPart );
		
		//fRaiseColumn
		textPart = new TextPartStyled();
		textPart.setText("\t"+TEXT_LOG_RaiseColumn);
		textPart.setStyleConstant(ConstantsFontColorLogView.STYLE_CATEGORY);		
		textStyleInfo.add(textPart);
		//fRaiseColumn value
		textPart = new TextPartStyled();
		textPart.setText(fRaiseColumn+" \n");
		textPart.setStyleConstant(ConstantsFontColorLogView.STYLE_VALUE);		
		textStyleInfo.add(textPart );
		
		//fBeSources
		textPart = new TextPartStyled();
		textPart.setText("\t"+TEXT_LOG_EBE);
		textPart.setStyleConstant(ConstantsFontColorLogView.STYLE_CATEGORY);		
		textStyleInfo.add(textPart);
		//fBeSources value
		textPart = new TextPartStyled();
		textPart.setText(fBeSources+" \n");
		textPart.setStyleConstant(ConstantsFontColorLogView.STYLE_VALUE);		
		textStyleInfo.add(textPart );
		
		//fPureATCombatTalent
		textPart = new TextPartStyled();
		textPart.setText("\t"+TEXT_LOG_PureATCombatTalent);
		textPart.setStyleConstant(ConstantsFontColorLogView.STYLE_CATEGORY);		
		textStyleInfo.add(textPart);
		//fPureATCombatTalent value
		textPart = new TextPartStyled();
		textPart.setText(fPureATCombatTalent+" \n");
		textPart.setStyleConstant(ConstantsFontColorLogView.STYLE_VALUE);		
		textStyleInfo.add(textPart );
						
		//fSpecializations
		textPart = new TextPartStyled();
		textPart.setText("\t"+TEXT_LOG_Specializations);
		textPart.setStyleConstant(ConstantsFontColorLogView.STYLE_CATEGORY);		
		textStyleInfo.add(textPart);
		//fSpecializations value
		textPart = new TextPartStyled();
		textPart.setText(fSpecializations+" \n");
		textPart.setStyleConstant(ConstantsFontColorLogView.STYLE_VALUE);		
		textStyleInfo.add(textPart );
		
		//fCompensationTalents
		textPart = new TextPartStyled();
		textPart.setText("\t"+TEXT_LOG_CompensationTalents);
		textPart.setStyleConstant(ConstantsFontColorLogView.STYLE_CATEGORY);		
		textStyleInfo.add(textPart);
		//fCompensationTalents value
		textPart = new TextPartStyled();
		textPart.setText(fCompensationTalents+" \n");
		textPart.setStyleConstant(ConstantsFontColorLogView.STYLE_VALUE);		
		textStyleInfo.add(textPart );
		
		return textStyleInfo;
	}

	@Override
	public String hasUnsetValues() {
		StringBuffer result = new StringBuffer();
		if(UNSET_TalentType.equals(fTalentType)){
			result.append(TEXT_UNSET_TalentType+"\n");
		}
		if(UNSET_AttributeFirst.equals(fAttributeFirst)){
			result.append(TEXT_UNSET_AttributeFirst+"\n");
		}
		if(UNSET_AttributeSecond.equals(fAttributeSecond)){
			result.append(TEXT_UNSET_AttributeSecond+"\n");
		}
		if(UNSET_AttributeThird.equals(fAttributeThird)){
			result.append(TEXT_UNSET_AttributeThird+"\n");
		}
		if(UNSET_RaiseColumn.equals(fRaiseColumn)){
			result.append(TEXT_UNSET_RaiseColumn+"\n");
		}
		if(new ArrayList<BeTypeValue>().equals(fBeSources)){
			result.append(TEXT_UNSET_EBE+"\n");
		}
		if(UNSET_PureATCombatTalent.equals(fPureATCombatTalent)){
			result.append(TEXT_UNSET_PureATCombatTalent+"\n");
		}
		if(new ArrayList<String>().equals(fSpecializations)){
			result.append(TEXT_UNSET_Specializations+"\n");
		}
		if(new ArrayList<CompensationTalentReference>().equals(fCompensationTalents)){
			result.append(TEXT_UNSET_CompensationTalents+"\n");
		}
		return result.toString();
	}

	/* (non-Javadoc)
	 * @see de.cbf.util.entity.facet.entities.FacetOfEntity#doMergeDataFrom(de.cbf.util.uuidheader.entities.UUIDHeader, boolean)
	 */
	@Override
	protected void doMergeDataFrom(UUIDHeader entity, boolean i_am_older)
			throws EntityMergeException {
		super.doMergeDataFrom(entity, i_am_older);
		if (entity instanceof FacetTalent) {
			FacetTalent other = (FacetTalent) entity;
			if(i_am_older){
				this.fTalentType = other.fTalentType;
				this.fAttributeFirst = other.fAttributeFirst;
				this.fAttributeSecond = other.fAttributeSecond;
				this.fAttributeThird = other.fAttributeThird;
				this.fRaiseColumn = other.fRaiseColumn;				
				this.fPureATCombatTalent = other.fPureATCombatTalent;				
				setBeSources(other.fBeSources);				
				this.fSpecializations.clear();
				this.fSpecializations.addAll(other.fSpecializations);
				this.fCompensationTalents.clear();
				this.fCompensationTalents.addAll(other.fCompensationTalents);
			}
		}else{
			String mergeEntityClass = entity == null? "null":entity.getClass().getName();
			String errorMsg ="EntityToMerge "+mergeEntityClass+" does not fit class:"+this.getClass().getName();
			throw new EntityMergeException(errorMsg);
		}
	}
	/* (non-Javadoc)
	 * @see de.cbf.util.entity.facet.entities.FacetOfEntity#setDeleted(java.lang.Long)
	 */
	@Override
	public void setDeleted(Long aDeleted) {		
		super.setDeleted(aDeleted);
		for (CompensationTalentReference reference : fCompensationTalents) {
			reference.setDeleted(aDeleted);			
		}
	}

	public String getTalentType(){
		return fTalentType;
	}

	public void setTalentType(String newTalentType) {
		if(newTalentType == null || newTalentType.equals(fTalentType)) return;
		String oldTalentType = this.fTalentType;
		this.fTalentType = newTalentType;
		propertyChangeSupport.fireIndexedPropertyChange(PN_TalentType, PI_TalentType,
				oldTalentType,this.fTalentType);	
	}	
	
	public String getAttributeFirst(){
		return fAttributeFirst;
	}

	public void setAttributeFirst(String newAttributeFirst) {
		if(newAttributeFirst == null || newAttributeFirst.equals(fAttributeFirst)) return;
		String oldAttributeFirst = this.fAttributeFirst;
		this.fAttributeFirst = newAttributeFirst;
		propertyChangeSupport.fireIndexedPropertyChange(PN_AttributeFirst, PI_AttributeFirst,
				oldAttributeFirst,this.fAttributeFirst);	
	}	 
	
	public String getAttributeSecond(){
		return fAttributeSecond;
	}

	public void setAttributeSecond(String newAttributeSecond) {
		if(newAttributeSecond == null || newAttributeSecond.equals(fAttributeSecond)) return;
		String oldAttributeSecond = this.fAttributeSecond;
		this.fAttributeSecond = newAttributeSecond;
		propertyChangeSupport.fireIndexedPropertyChange(PN_AttributeSecond, PI_AttributeSecond,
				oldAttributeSecond,this.fAttributeSecond);	
	}	
	
	public String getAttributeThird(){
		return fAttributeThird;
	}

	public void setAttributeThird(String newAttributeThird) {
		if(newAttributeThird == null || newAttributeThird.equals(fAttributeThird)) return;
		String oldAttributeThird = this.fAttributeThird;
		this.fAttributeThird = newAttributeThird;
		propertyChangeSupport.fireIndexedPropertyChange(PN_AttributeThird, PI_AttributeThird,
				oldAttributeThird,this.fAttributeThird);	
	}	
	
	public Integer getRaiseColumn(){
		return fRaiseColumn;
	}
	public void setRaiseColumn(Integer newRaiseColumn) {
		if(newRaiseColumn == null || newRaiseColumn.equals(fRaiseColumn)) return;
		Integer oldRaiseColumn = this.fRaiseColumn;
		this.fRaiseColumn = newRaiseColumn;
		propertyChangeSupport.fireIndexedPropertyChange(PN_RaiseColumn, PI_RaiseColumn,
				oldRaiseColumn,this.fRaiseColumn);	
	}	
	
	public Boolean getPureATCombatTalent(){
		return fPureATCombatTalent;
	}
	public void setPureATCombatTalent(Boolean newPureATCombatTalent) {
		if(newPureATCombatTalent == null || newPureATCombatTalent.equals(fPureATCombatTalent)) return;
		Boolean oldPureATCombatTalent = this.fPureATCombatTalent;
		this.fPureATCombatTalent = newPureATCombatTalent;
		propertyChangeSupport.fireIndexedPropertyChange(PN_PureATCombatTalent, PI_PureATCombatTalent,
				oldPureATCombatTalent,this.fPureATCombatTalent);	
	}	
	
	public List<String> getSpecializations(){
		return new ArrayList<String>(fSpecializations);
	}
	
	public boolean addSpecialization(String specialization){
		boolean result = fSpecializations.add(specialization);
		propertyChangeSupport.fireIndexedPropertyChange(PN_Specializations, PI_Specializations,
				null,this.fSpecializations);
		return result;
	}
	
	public boolean removeSpecialization(String specialization){
		boolean result = fSpecializations.remove(specialization);
		propertyChangeSupport.fireIndexedPropertyChange(PN_Specializations, PI_Specializations,
				null,this.fSpecializations);
		return result;
	}

	public void setSpecializations(List<String> newSpecializations) {
		if(newSpecializations == null || newSpecializations.equals(fSpecializations)) return;
		this.fSpecializations.clear();
		this.fSpecializations.addAll(newSpecializations);
		propertyChangeSupport.fireIndexedPropertyChange(PN_Specializations, PI_Specializations,
				null,this.fSpecializations);	
	}
	
	public List<CompensationTalentReference> getCompensationTalents(){
		return new ArrayList<CompensationTalentReference>(fCompensationTalents);
	}
	
	public boolean addCompensationTalent(CompensationTalentReference compensationTalent){
		boolean result = fCompensationTalents.add(compensationTalent);
		propertyChangeSupport.fireIndexedPropertyChange(PN_CompensationTalents, PI_CompensationTalents,
				null,this.fCompensationTalents);
		return result;
	}
	
	public boolean removeCompensationTalent(CompensationTalentReference compensationTalent){
		boolean result = fCompensationTalents.remove(compensationTalent);
		propertyChangeSupport.fireIndexedPropertyChange(PN_CompensationTalents, PI_CompensationTalents,
				null,this.fCompensationTalents);
		return result;
	}

	public void setCompensationTalents(List<CompensationTalentReference> newCompensationTalents) {
		if(newCompensationTalents == null || newCompensationTalents.equals(fCompensationTalents)) return;
		this.fCompensationTalents.clear();
		this.fCompensationTalents.addAll(newCompensationTalents);
		propertyChangeSupport.fireIndexedPropertyChange(PN_CompensationTalents, PI_CompensationTalents,
				null,this.fCompensationTalents);	
	}

	public List<BeTypeValue> getBeSources(){
		return new ArrayList<BeTypeValue>(fBeSources);
	}
	
	public boolean addBeSource(BeTypeValue beTypeValue){
		boolean result = fBeSources.add(beTypeValue);
		beTypeValue.getPropertyChangeSupport().addPropertyChangeListener(getPCL_TypeValue());
		propertyChangeSupport.fireIndexedPropertyChange(PN_CompensationTalents, PI_CompensationTalents,
				null,this.fBeSources);
		return result;
	}
	
	public boolean removeBeSource(BeTypeValue compensationTalent){
		boolean result = fBeSources.remove(compensationTalent);
		propertyChangeSupport.fireIndexedPropertyChange(PN_CompensationTalents, PI_CompensationTalents,
				null,this.fBeSources);
		return result;
	}

	public void setBeSources(List<BeTypeValue> newBeSources) {
		if(newBeSources == null || newBeSources.equals(fBeSources)) return;
		for (BeTypeValue beTypeValue : fBeSources) {
			beTypeValue.getPropertyChangeSupport().removePropertyChangeListener(getPCL_TypeValue());
		}
		this.fBeSources.clear();
		this.fBeSources.addAll(newBeSources);
		for (BeTypeValue beTypeValue : newBeSources) {
			beTypeValue.getPropertyChangeSupport().addPropertyChangeListener(getPCL_TypeValue());
		}
		propertyChangeSupport.fireIndexedPropertyChange(PN_BeSources, PI_BeSources,
				null,this.fBeSources);	
	}
	
	@XmlTransient
	protected PCL_TypeValue pcl_TypeValue;
	protected PCL_TypeValue getPCL_TypeValue(){
		if(pcl_TypeValue == null){
			pcl_TypeValue = new PCL_TypeValue();
		}
		return pcl_TypeValue;
	}	
	protected class PCL_TypeValue implements PropertyChangeListener{
		@Override
		public void propertyChange(PropertyChangeEvent evt) {
			propertyChangeSupport.fireIndexedPropertyChange(
					PN_BeSources, PI_BeSources, null, fBeSources);
		}		
	}
	

	
}
